// =====================================================================
// <copyright file="PropertyValidationHelper.cs" author="David R. Guindo">
// 	Copyright (C) 2013. All rights reserved.
// </copyright>
// =====================================================================
// This code is released under the terms of the Apache 2.0 license, 
// http://apache.org/licenses/LICENSE-2.0.html
// =====================================================================

namespace AppBlock.Core
{
    using System;
    using System.Globalization;
    using System.Linq.Expressions;
    using AppBlock.Core.Resources;
    using AppBlock.Core.Validations;

    /// <summary>
    /// </summary>
    public static class PropertyValidationHelper
    {
        /// <summary>
        ///     Dates the in range.
        /// </summary>
        /// <param name="validation">The validation entity for add errors.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        /// <param name="begin">The begin.</param>
        /// <param name="end">The end.</param>
        /// <param name="admitNull">if set to <c>true</c> admit null values.</param>
        public static void DateInRange(
            IValidation validation,
            string propertyName,
            DateTime? value,
            DateTime? begin,
            DateTime? end,
            bool admitNull)
        {
            if (value == null && !admitNull)
            {
                validation.AddError(ValidationType.RequiredValue, propertyName, "null");
            }

            if (value != null && admitNull)
            {
                if (begin == null)
                {
                    begin = new DateTime(1753, 1, 1); // Min value for SQL
                }

                if (value < begin)
                {
                    validation.AddError(
                        ValidationType.InvalidMinValue, propertyName, ((DateTime) begin).ToString("yyyy-MM-dd HH:mm"));
                }

                if (end != null && value > end)
                {
                    validation.AddError(
                        ValidationType.ValueExceeded, propertyName, ((DateTime) end).ToString("yyyy-MM-dd HH:mm"));
                }
            }
        }

        /// <summary>
        ///     Determines if the specified property name is in especified interval.
        /// </summary>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        /// <param name="minValue">The min value.</param>
        /// <param name="maxValue">The max value.</param>
        public static void IsInIntervalInt(
            IValidation validation, string propertyName, int value, int minValue, int maxValue)
        {
            if (value < minValue || value > maxValue)
            {
                validation.AddError(
                    ValidationType.NotInRange, propertyName, value.ToString(CultureInfo.InvariantCulture));
            }
        }

        /// <summary>
        ///     Determines if the specified property name is ghreater than especified value.
        /// </summary>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        /// <param name="minValue">The min value.</param>
        public static void IsMayorInt(IValidation validation, string propertyName, int value, int minValue)
        {
            if (value < minValue)
            {
                validation.AddError(
                    ValidationType.InvalidMinValue, propertyName, minValue.ToString(CultureInfo.InvariantCulture));
            }
        }

        /// <summary>
        ///     Determines whether [is positive int] [the specified property name].
        /// </summary>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        public static void IsPositiveInt(IValidation validation, string propertyName, int? value)
        {
            if (value == null)
            {
                validation.AddError(ValidationType.RequiredValue, propertyName, "null");
            }

            if (value < 0)
            {
                validation.AddError(ValidationType.InvalidMinValue, propertyName, "0");
            }
        }

        /// <summary>
        ///     Determines whether [is positive long] [the specified field name].
        /// </summary>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        public static void IsPositiveLong(IValidation validation, string propertyName, long? value)
        {
            if (value == null)
            {
                validation.AddError(ValidationType.RequiredValue, propertyName, "null");
            }

            if (value < 0)
            {
                validation.AddError(ValidationType.ValueExceeded, propertyName, "0");
            }
        }

        /// <summary>
        ///     Determines if the specified property name is a valid identifier.
        /// </summary>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        public static void IsValidGuid(IValidation validation, string propertyName, Guid value)
        {
            if (value == Guid.Empty)
            {
                validation.AddError(ValidationType.InvalidIdentifier, propertyName, value.ToString());
            }
        }

        /// <summary>
        ///     Validates the string.
        /// </summary>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">The name.</param>
        /// <param name="value">The value.</param>
        /// <param name="minLength">Length of the min.</param>
        /// <param name="maxLength">Length of the max.</param>
        /// <param name="admitNull">if set to <c>true</c> [admit null].</param>
        /// <returns></returns>
        public static void ValidateString(
            IValidation validation, string propertyName, string value, int minLength, int maxLength, bool admitNull)
        {
            if (!admitNull)
            {
                if (value == null)
                {
                    validation.AddError(ValidationType.RequiredValue, propertyName, "null");
                }

                if (string.IsNullOrWhiteSpace(value))
                {
                    validation.AddError(ValidationType.InvalidValue, propertyName, "(Empty)");
                }
            }

            if (value != null)
            {
                if (maxLength != int.MaxValue && value.Length > maxLength)
                {
                    validation.AddError(
                        ValidationType.ValueExceeded, propertyName, maxLength.ToString(CultureInfo.InvariantCulture));
                }

                if (value.Length < minLength)
                {
                    validation.AddError(
                        ValidationType.InvalidMinValue, propertyName, minLength.ToString(CultureInfo.InvariantCulture));
                }
            }
        }

        /// <summary>
        ///     Determines whether [is valid identifier] [the specified validation].
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value of the identifier.</param>
        public static void IsValidIdentifier<T>(IValidation validation, string propertyName, T value)
        {
            if (value.Equals(default(T)))
            {
                validation.AddError(ValidationType.InvalidIdentifier, propertyName, value.ToString());
            }
        }

        /// <summary>
        ///     Determines if is null the specified value.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="validation">The validation.</param>
        /// <param name="propertyName">Name of the property.</param>
        /// <param name="value">The value.</param>
        public static void IsNotNull<T>(IValidation validation, string propertyName, T value)
        {
            if (value.Equals(null))
            {
                validation.AddError(ValidationType.InvalidIdentifier, propertyName, value.ToString());
            }
        }

        public static void IsNotNullOrWhiteSpace<T>(IValidation validation, string value, Expression<Func<T>> prop)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                var propName = ReflectionHelper.GetPropertyName(prop);
                if (validation == null)
                {
                    throw ErrorMsg.IsNotNullOrWhiteSpace(propName);
                }

                validation.AddError(ValidationType.InvalidIdentifier, propName, value);
            }
        }
    }
}